/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.mocamorena.persistence.dao.impl;

import br.com.mocamorena.exception.PersistenciaException;
import br.com.mocamorena.model.Cliente;
import br.com.mocamorena.model.Endereco;
import br.com.mocamorena.model.Telefone;
import br.com.mocamorena.model.constant.EstadoCivil;
import br.com.mocamorena.model.constant.Natureza;
import br.com.mocamorena.model.constant.Sexo;
import br.com.mocamorena.model.constant.TipoTelefone;
import br.com.mocamorena.model.constant.UnidadeFederativa;
import br.com.mocamorena.persistence.GerenciadorDeConexao;
import br.com.mocamorena.persistence.dao.ClienteDao;
import br.com.mocamorena.view.DisplayFilter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * @author Diego
 */
public class ClienteDaoImpl implements ClienteDao {

    private Connection conn;
    private PreparedStatement pr;
    private ResultSet rs;

    @Override
    public boolean inserir(Cliente cliente) throws PersistenciaException {
        if (cliente == null) {
            throw new PersistenciaException("Não foi informado o cliente a cadastrar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("INSERT INTO CLIENTE(ID, BLOQUEADO, NATUREZA, NOME, EMPRESA, REPRESENTANTE, CADASTRO_PESSOA, SEXO, ESTADO_CIVIL, DATA_NASCIMENTO, RG, ORG_EXP, DATA_CADASTRO, OBSERVACAO, ID_ENDERECO, COMPLEMENTO, SHADOW) VALUES(NULL, FALSE, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURDATE(), ?, ?, ?, FALSE);",
                    Statement.RETURN_GENERATED_KEYS);
            pr.setString(1, cliente.getNatureza().name());
            pr.setString(2, cliente.getNome());
            pr.setString(3, cliente.getEmpresa());
            pr.setString(4, cliente.getRepresentante());
            pr.setString(5, cliente.getCadastroPessoa());
            pr.setString(6, cliente.getSexo() != null ? cliente.getSexo().name() : null);
            pr.setString(7, cliente.getEstadoCivil() != null ? cliente.getEstadoCivil().name() : null);
            pr.setDate(8, cliente.getDataNascimento()!= null ? new java.sql.Date(cliente.getDataNascimento().getTime()) : null);
            pr.setString(9, cliente.getRg());
            pr.setString(10, cliente.getOrgExp());
            pr.setString(11, cliente.getObservacao());
            pr.setLong(12, cliente.getEndereco() != null ? cliente.getEndereco().getId() : 0);
            pr.setString(13, cliente.getEndereco() != null ? cliente.getEndereco().getComplemento() : null);
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
                rs = pr.getGeneratedKeys();
                rs.first();
                long id = rs.getLong(1);
                cliente.setId(id);

                inserirTelefones(cliente);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível cadastrar o cliente.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return sucesso;
    }

    @Override
    public boolean atualizar(Cliente cliente) throws PersistenciaException {
        if (cliente == null) {
            throw new PersistenciaException("Não foi informado o cliente a atualizar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE CLIENTE SET BLOQUEADO=?, NATUREZA=?, NOME=?, EMPRESA=?, REPRESENTANTE=?, CADASTRO_PESSOA=?, SEXO=?, ESTADO_CIVIL=?, DATA_NASCIMENTO=?, RG=?, ORG_EXP=?, OBSERVACAO=?, ID_ENDERECO=?, COMPLEMENTO=? WHERE ID=?;");
            pr.setBoolean(1, cliente.isBloqueado());
            pr.setString(2, cliente.getNatureza().name());
            pr.setString(3, cliente.getNome());
            pr.setString(4, cliente.getEmpresa());
            pr.setString(5, cliente.getRepresentante());
            pr.setString(6, cliente.getCadastroPessoa());
            pr.setString(7, cliente.getSexo() != null ? cliente.getSexo().name() : null);
            pr.setString(8, cliente.getEstadoCivil() != null ? cliente.getEstadoCivil().name() : null);
            pr.setDate(9, cliente.getDataNascimento() != null ? new java.sql.Date(cliente.getDataNascimento().getTime()) : null);
            pr.setString(10, cliente.getRg());
            pr.setString(11, cliente.getOrgExp());
            pr.setString(12, cliente.getObservacao());
            pr.setLong(13, cliente.getEndereco() != null ? cliente.getEndereco().getId() : 0);
            pr.setString(14, cliente.getEndereco() != null ? cliente.getEndereco().getComplemento() : null);
            pr.setLong(15, cliente.getId());

            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                inserirTelefones(cliente);
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível atualizar o cliente.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public boolean excluir(Cliente cliente) throws PersistenciaException {
        if (cliente == null) {
            throw new PersistenciaException("Não foi informado o cliente a excluir.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE CLIENTE SET SHADOW=TRUE WHERE ID=?;");
            pr.setLong(1, cliente.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível excluir o cliente.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public List<Cliente> listarTodos(int... limits) throws PersistenciaException {
        List<Cliente> lista = new ArrayList<Cliente>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE ORDER BY C.LAST_UPDATE DESC LIMIT ?, ?");
            pr.setInt(1, limits[0]);
            pr.setInt(2, limits[1]);
            rs = pr.executeQuery();
            while (rs.next()) {
                Cliente cliente = this.criarCliente(rs);
                lista.add(cliente);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os clientes atualizados recentemente.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    @Override
    public List<Cliente> listarPeloNome(String nome, DisplayFilter displayFilter) throws PersistenciaException {
        List<Cliente> lista = new ArrayList<Cliente>();
        try {
            conn = GerenciadorDeConexao.abreConexao();            
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE AND C.NOME LIKE ? AND C.BLOQUEADO=? ORDER BY C.NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE AND C.NOME LIKE ? ORDER BY C.NOME");
            }
            pr.setString(1, "%" + nome + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Cliente cliente = this.criarCliente(rs);
                lista.add(cliente);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os clientes pelo nome.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    @Override
    public List<Cliente> listarPeloCpfECnpj(String cadastroPessoa, DisplayFilter displayFilter) throws PersistenciaException {
        List<Cliente> lista = new ArrayList<Cliente>();
        try {
            conn = GerenciadorDeConexao.abreConexao();            
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE AND C.CADASTRO_PESSOA=? AND C.BLOQUEADO=? ORDER BY C.CADASTRO_PESSOA");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE AND C.CADASTRO_PESSOA=? ORDER BY C.CADASTRO_PESSOA");
            }
            pr.setString(1, cadastroPessoa);
            rs = pr.executeQuery();
            while (rs.next()) {
                Cliente cliente = this.criarCliente(rs);
                lista.add(cliente);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os clientes pelo documento.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    @Override
    public List<Cliente> listarPeloCep(String cep, DisplayFilter displayFilter) throws PersistenciaException {
        List<Cliente> lista = new ArrayList<Cliente>();
        try {
            conn = GerenciadorDeConexao.abreConexao();            
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE AND E.CEP=? AND C.BLOQUEADO=? ORDER BY C.NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT C.ID, C.BLOQUEADO, C.NATUREZA, C.NOME, C.EMPRESA, C.REPRESENTANTE, C.CADASTRO_PESSOA, C.SEXO, C.ESTADO_CIVIL, C.DATA_NASCIMENTO, C.RG, C.ORG_EXP, C.DATA_CADASTRO, C.OBSERVACAO, C.COMPLEMENTO, E.ID AS ID_ENDERECO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM CLIENTE C LEFT JOIN ENDERECO E ON C.ID_ENDERECO = E.ID WHERE C.SHADOW=FALSE AND E.CEP=? ORDER BY C.NOME");
            }
            pr.setString(1, cep);
            rs = pr.executeQuery();
            while (rs.next()) {
                Cliente cliente = this.criarCliente(rs);
                lista.add(cliente);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os clientes pelo nome.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    private void inserirTelefones(Cliente cliente) throws PersistenciaException {
        try {
            pr = conn.prepareStatement("DELETE FROM TELEFONE_CLIENTE WHERE ID_CLIENTE=?;");
            pr.setLong(1, cliente.getId());
            pr.executeUpdate();

            pr = conn.prepareStatement("INSERT INTO TELEFONE_CLIENTE(ID, TIPO, DDD, NUMERO, RAMAL, ID_CLIENTE) VALUES(NULL, ?, ?, ?, ?, ?);");
            List<Telefone> telefonesList = cliente.getTelefonesList();
            for (Telefone telefone : telefonesList) {
                pr.setString(1, telefone.getTipo().name());
                pr.setString(2, telefone.getDdd());
                pr.setString(3, telefone.getNumero());
                pr.setString(4, telefone.getRamal());
                pr.setLong(5, cliente.getId());
                pr.executeUpdate();
                pr.clearParameters();
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível inserir os telefones do associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        }
    }

    @Override
    public void getTelefones(Cliente cliente) throws PersistenciaException {
        try {
            cliente.setTelefonesList(new ArrayList<Telefone>());
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT T.ID, T.TIPO, T.DDD, T.NUMERO, T.RAMAL FROM TELEFONE_CLIENTE T INNER JOIN CLIENTE C ON T.ID_CLIENTE=? AND T.ID_CLIENTE = C.ID ORDER BY T.ID;");
            pr.setLong(1, cliente.getId());
            rs = pr.executeQuery();
            while (rs.next()) {
                Telefone telefone = new Telefone(rs.getLong("ID"));
                telefone.setTipo(TipoTelefone.valueOf(rs.getString("TIPO")));
                telefone.setDdd(rs.getString("DDD"));
                telefone.setNumero(rs.getString("NUMERO"));
                telefone.setRamal(rs.getString("RAMAL"));

                cliente.getTelefonesList().add(telefone);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os telefones do cliente.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
    }

    private Cliente criarCliente(ResultSet rs) throws PersistenciaException {
        Cliente cliente = null;
        try {
            cliente = new Cliente(rs.getLong("ID"));
            cliente.setBloqueado(rs.getBoolean("BLOQUEADO"));
            cliente.setNatureza(Natureza.valueOf(rs.getString("NATUREZA")));
            cliente.setNome(rs.getString("NOME"));
            cliente.setEmpresa(rs.getString("EMPRESA"));
            cliente.setRepresentante(rs.getString("REPRESENTANTE"));
            cliente.setCadastroPessoa(rs.getString("CADASTRO_PESSOA"));
            cliente.setSexo(rs.getString("SEXO") != null ? Sexo.valueOf(rs.getString("SEXO")) : null);
            cliente.setEstadoCivil(rs.getString("ESTADO_CIVIL") != null ? EstadoCivil.valueOf(rs.getString("ESTADO_CIVIL")) : null);
            cliente.setDataNascimento(rs.getDate("DATA_NASCIMENTO") != null ? new Date(rs.getDate("DATA_NASCIMENTO").getTime()) : null);
            cliente.setRg(rs.getString("RG"));
            cliente.setOrgExp(rs.getString("ORG_EXP"));
            cliente.setDataCadastro(new Date(rs.getDate("DATA_CADASTRO").getTime()));
            cliente.setObservacao(rs.getString("OBSERVACAO"));

            long id = rs.getLong("ID_ENDERECO");
            if (id > 0) {
                Endereco endereco = new Endereco(id);
                endereco.setCep(rs.getString("CEP"));
                endereco.setLogradouro(rs.getString("LOGRADOURO"));
                endereco.setBairro(rs.getString("BAIRRO"));
                endereco.setCidade(rs.getString("CIDADE"));
                endereco.setUf(UnidadeFederativa.valueOf(rs.getString("ESTADO")));
                endereco.setComplemento(rs.getString("COMPLEMENTO"));
                cliente.setEndereco(endereco);
            }
        } catch (SQLException sqlex) {
            StringBuilder msg = new StringBuilder("Não foi possível obter os dados do cliente.");
            msg.append("\nMotivo: ").append(sqlex.getMessage());
            throw new PersistenciaException(msg.toString());
        }
        return cliente;
    }
}
